import { useState, useEffect, useCallback } from "react";
import { IrohClientImpl } from "./client";
import {
  IrohClient,
  IrohNode,
  IrohDocument,
  FileTransferProgress,
} from "./index";

interface UseIrohState {
  client: IrohClient | null;
  node: IrohNode | null;
  documents: IrohDocument[];
  isInitialized: boolean;
  isLoading: boolean;
  error: string | null;
}

interface UseIrohResult extends UseIrohState {
  initializeNode: () => Promise<void>;
  createDocument: (name: string) => Promise<IrohDocument | null>;
  deleteDocument: (id: string) => Promise<boolean>;
  shareDocument: (id: string) => Promise<string | null>;
  receiveDocument: (
    ticket: string,
    onProgress?: (progress: FileTransferProgress) => void,
  ) => Promise<IrohDocument | null>;
  refreshDocuments: () => Promise<void>;
  shutdown: () => Promise<void>;
}

/**
 * React hook for Iroh functionality
 */
export function useIroh(): UseIrohResult {
  const [state, setState] = useState<UseIrohState>({
    client: null,
    node: null,
    documents: [],
    isInitialized: false,
    isLoading: false,
    error: null,
  });

  const setLoading = useCallback((loading: boolean) => {
    setState((prev) => ({ ...prev, isLoading: loading }));
  }, []);

  const setError = useCallback((error: string | null) => {
    setState((prev) => ({ ...prev, error }));
  }, []);

  const initializeNode = useCallback(async () => {
    try {
      setLoading(true);
      setError(null);

      const client = new IrohClientImpl();
      const node = await client.createNode();
      const documents = await client.listDocuments();

      setState((prev) => ({
        ...prev,
        client,
        node,
        documents,
        isInitialized: true,
      }));
    } catch (error) {
      setError(
        error instanceof Error ? error.message : "Failed to initialize node",
      );
    } finally {
      setLoading(false);
    }
  }, [setLoading, setError]);

  const createDocument = useCallback(
    async (name: string): Promise<IrohDocument | null> => {
      if (!state.client) {
        setError("Client not initialized");
        return null;
      }

      try {
        setLoading(true);
        setError(null);

        const document = await state.client.createDocument(name);

        setState((prev) => ({
          ...prev,
          documents: [...prev.documents, document],
        }));

        return document;
      } catch (error) {
        setError(
          error instanceof Error ? error.message : "Failed to create document",
        );
        return null;
      } finally {
        setLoading(false);
      }
    },
    [state.client, setLoading, setError],
  );

  const deleteDocument = useCallback(
    async (id: string): Promise<boolean> => {
      if (!state.client) {
        setError("Client not initialized");
        return false;
      }

      try {
        setLoading(true);
        setError(null);

        const success = await state.client.deleteDocument(id);

        if (success) {
          setState((prev) => ({
            ...prev,
            documents: prev.documents.filter((doc) => doc.id !== id),
          }));
        }

        return success;
      } catch (error) {
        setError(
          error instanceof Error ? error.message : "Failed to delete document",
        );
        return false;
      } finally {
        setLoading(false);
      }
    },
    [state.client, setLoading, setError],
  );

  const shareDocument = useCallback(
    async (id: string): Promise<string | null> => {
      if (!state.client) {
        setError("Client not initialized");
        return null;
      }

      try {
        setLoading(true);
        setError(null);

        const ticket = await state.client.shareDocument(id);
        return ticket;
      } catch (error) {
        setError(
          error instanceof Error ? error.message : "Failed to share document",
        );
        return null;
      } finally {
        setLoading(false);
      }
    },
    [state.client, setLoading, setError],
  );

  const receiveDocument = useCallback(
    async (
      ticket: string,
      onProgress?: (progress: FileTransferProgress) => void,
    ): Promise<IrohDocument | null> => {
      if (!state.client) {
        setError("Client not initialized");
        return null;
      }

      try {
        setLoading(true);
        setError(null);

        const document = await state.client.receiveDocument(ticket, onProgress);

        setState((prev) => ({
          ...prev,
          documents: [...prev.documents, document],
        }));

        return document;
      } catch (error) {
        setError(
          error instanceof Error ? error.message : "Failed to receive document",
        );
        return null;
      } finally {
        setLoading(false);
      }
    },
    [state.client, setLoading, setError],
  );

  const refreshDocuments = useCallback(async () => {
    if (!state.client) {
      return;
    }

    try {
      setLoading(true);
      const documents = await state.client.listDocuments();

      setState((prev) => ({
        ...prev,
        documents,
      }));
    } catch (error) {
      setError(
        error instanceof Error ? error.message : "Failed to refresh documents",
      );
    } finally {
      setLoading(false);
    }
  }, [state.client, setLoading, setError]);

  const shutdown = useCallback(async () => {
    if (!state.client) {
      return;
    }

    try {
      await state.client.shutdown();

      setState({
        client: null,
        node: null,
        documents: [],
        isInitialized: false,
        isLoading: false,
        error: null,
      });
    } catch (error) {
      setError(error instanceof Error ? error.message : "Failed to shutdown");
    }
  }, [state.client, setError]);

  return {
    ...state,
    initializeNode,
    createDocument,
    deleteDocument,
    shareDocument,
    receiveDocument,
    refreshDocuments,
    shutdown,
  };
}

/**
 * Hook for managing file transfer progress
 */
export function useFileTransfer() {
  const [transfers, setTransfers] = useState<Map<string, FileTransferProgress>>(
    new Map(),
  );

  const startTransfer = useCallback((transferId: string) => {
    setTransfers(
      (prev) =>
        new Map(
          prev.set(transferId, {
            transferred: 0,
            total: 100,
            percentage: 0,
            status: "pending",
          }),
        ),
    );
  }, []);

  const updateProgress = useCallback(
    (transferId: string, progress: FileTransferProgress) => {
      setTransfers((prev) => new Map(prev.set(transferId, progress)));
    },
    [],
  );

  const completeTransfer = useCallback((transferId: string) => {
    setTransfers((prev) => {
      const newMap = new Map(prev);
      newMap.delete(transferId);
      return newMap;
    });
  }, []);

  const getProgress = useCallback(
    (transferId: string): FileTransferProgress | null => {
      return transfers.get(transferId) || null;
    },
    [transfers],
  );

  return {
    transfers: Array.from(transfers.entries()),
    startTransfer,
    updateProgress,
    completeTransfer,
    getProgress,
  };
}

